#include <iostream>
#include <cstring>
#include <string>
#include <sys/sendfile.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mysql.h>

std::string UrlEncode(const std::string& szToEncode)
{
    std::string src = szToEncode;
    char hex[] = "0123456789ABCDEF";
    std::string dst;
 
    for (size_t i = 0; i < src.size(); ++i)
    {
        unsigned char cc = src[i];
        if (isascii(cc))
        {
            if (cc == ' ')
            {
                dst += "%20";
            }
            else
                dst += cc;
        }
        else
        {
            unsigned char c = static_cast<unsigned char>(src[i]);
            dst += '%';
            dst += hex[c / 16];
            dst += hex[c % 16];
        }
    }
    return dst;
}
 
std::string UrlDecode(const std::string& szToDecode)
{
    std::string result;
    int hex = 0;
    for (size_t i = 0; i < szToDecode.length(); ++i)
    {
        switch (szToDecode[i])
        {
        case '+':
            result += ' ';
            break;
        case '%':
            if (isxdigit(szToDecode[i + 1]) && isxdigit(szToDecode[i + 2]))
            {
                std::string hexStr = szToDecode.substr(i + 1, 2);
                hex = strtol(hexStr.c_str(), 0, 16);
                //字母和数字[0-9a-zA-Z]、一些特殊符号[$-_.+!*'(),] 、以及某些保留字[$&+,/:;=?@]
                //可以不经过编码直接用于URL
                if (!((hex >= 48 && hex <= 57) || //0-9
                    (hex >=97 && hex <= 122) ||   //a-z
                    (hex >=65 && hex <= 90) ||    //A-Z
                    //一些特殊符号及保留字[$-_.+!*'(),]  [$&+,/:;=?@]
                    hex == 0x21 || hex == 0x24 || hex == 0x26 || hex == 0x27 || hex == 0x28 || hex == 0x29
                    || hex == 0x2a || hex == 0x2b|| hex == 0x2c || hex == 0x2d || hex == 0x2e || hex == 0x2f
                    || hex == 0x3A || hex == 0x3B|| hex == 0x3D || hex == 0x3f || hex == 0x40 || hex == 0x5f
                    ))
                {
                    result += char(hex);
                    i += 2;
                }
                else result += '%';
            }else {
                result += '%';
            }
            break;
        default:
            result += szToDecode[i];
            break;
        }
    }
    return result;
}
bool GetQueryString(std::string& query)
{
    std::string method = getenv("METHOD");
    std::cerr << "method: " + method << std::endl;
    if (method == "GET"){
        query = getenv("QUERY");
        std::cerr << "query_string: " + query << std::endl;
        return true;
    }
    else if (method == "POST"){
        int content_length = atoi(getenv("Content-Length"));
        std::cerr << "debug: content_length:" << content_length << std::endl;
        char ch;
        while (content_length){
            read(0, &ch, 1);
            query += ch;
            content_length--;
        }
        std::cerr << "query_string: " + query << std::endl;
        return true;
    }
    else{
        return false;
    }
}

void CutString(const std::string& in, const std::string sep, std::string& out1, std::string& out2)
{
    size_t pos = in.find(sep);
    if (pos != std::string::npos){
        out1 = in.substr(0, pos);
        out2 = in.substr(pos+sep.size());
    }
}

bool implement(std::string& sql)
{
    MYSQL* con=mysql_init(nullptr);
    mysql_set_character_set(con, "utf8");
    if(nullptr==mysql_real_connect(con,"127.0.0.1","http_test","12345678","http_test",3306,nullptr,0))
    {
        std::cerr<<"connect mysql fail"<<std::endl;
        return 1;
    }
    std::cerr << "connect mysql success!" << std::endl;
    int ret = mysql_query(con, sql.c_str());
    std::cerr << ret << std::endl;
    mysql_close(con);
    return ret == 0;
}

bool Insert(std::string& name, std::string& value)
{
    std::string sql;
    sql = "insert into user (name,password) values('" + name + "','" + value + "');";
    std::cerr << sql << std::endl;
    return implement(sql);
}

int Select(std::string& name, std::string& pwd)
{
    std::string sql;
    sql = "select * from user where name='" + name + "';";
    //sql = "select * from user";
    std::cerr << sql << std::endl;
   MYSQL* con=mysql_init(nullptr);
    mysql_set_character_set(con, "utf8");
    if(nullptr==mysql_real_connect(con,"127.0.0.1","http_test","12345678","http_test",3306,nullptr,0))
    {
        std::cerr<<"fail"<<std::endl;
        return 1;
    }
    if (mysql_query(con, sql.c_str())){
        return -1;
    }
    // 获取查询结果
    MYSQL_RES* sqlres = mysql_store_result(con);
    if (sqlres == nullptr) return 1;
    my_ulonglong num = mysql_num_rows(sqlres);
    if (num == 0){
        // 账户不存在
        return 1;
    }
    MYSQL_ROW line = mysql_fetch_row(sqlres);
    std::cerr << line[0] <<":" << line[1] << std::endl;
    //std::cerr << pwd << std::endl;
    if (line[1] != pwd){
        //密码不正确
        return 2;
    }
    mysql_close(con);
    mysql_free_result(sqlres);
    return 0;
}
bool Compare(std::string s1, std::string s2)
{
    int size1 = s1.size(), size2 = s2.size();
    if (size1 != size2) return false;
    for (int i = 0; i < size1; ++i)
    {
        if (s1[i] != s2[i])
        return false;
    }
    return true;
}
int main()
{
    std::cerr<<"------------------------mysql-begin--------------------------"<<std::endl;
    std::string query;
    if (!GetQueryString(query)){
        exit(7);
    }
    std::string name;
    std::string password;
    CutString(query, "&", name, password);
    if (name == ""){
        return 0;
    }
    std::cerr << "name:"<<name << std::endl;
    std::cerr << "password:"<<password << std::endl;

    std::string name_key;
    std::string name_value;
    CutString(name, "=", name_key, name_value);
    
    std::string pwd_key;
    std::string pwd_value;
    CutString(password, "=", pwd_key, pwd_value);

    name_value = UrlDecode(name_value);
    pwd_value = UrlDecode(pwd_value);
    std::cerr << name_key +" "+name_value+ " : " +pwd_key+" "+ pwd_value<< std::endl;
    bool flg=false;
    bool res = Compare(std::string("login-name") , name_key); 
    std::cerr << res << std::endl;
     if (name_value == ""||pwd_value==""){
        // 信息错误
        std::cout << "<head><meta charset=\"UTF-8\"></head>" << std::endl;
        std::cout << "<body><h1>信息错误</h1></body>" << std::endl;
    }
    else if (res){ //登陆
        //查询
        int ret = Select(name_value, pwd_value);
        if (ret == 0){//成功
            struct stat st;
            stat("/home/zgj/lesson/HttpServer/wwwroot/calc.html", &st);
            int fd = open("/home/zgj/lesson/HttpServer/wwwroot/calc.html", O_RDONLY);
            std::cerr << "fd:" << fd << std::endl;
            sendfile(1, fd, nullptr, st.st_size);
            std::cerr << "用户：" + name_value + " 登录成功"<< std::endl;
            close(fd);
        }
        else if (ret == 1){
            // 账号不存在
            std::cout << "<head><meta charset=\"UTF-8\"></head>" << std::endl;
            std::cout << "<body><h1>账号不存在</h1></body>" << std::endl;
        }
        else if (ret == 2){
            // 密码错误
            std::cout << "<head><meta charset=\"UTF-8\"></head>" << std::endl;
            std::cout << "<body><h1>密码错误</h1></body>" << std::endl;
        }
    }
    else{//注册
        if (Insert(name_value, pwd_value)){
            std::cerr << "用户：" + name_value + " " + "密码：" + pwd_value + " 注册成功"<< std::endl;
            struct stat st;
            stat("/home/zgj/lesson/HttpServer/wwwroot/index.html", &st);
            int fd = open("/home/zgj/lesson/HttpServer/wwwroot/index.html", O_RDONLY);
            sendfile(1, fd, nullptr, st.st_size);
            close(fd);
        }
        else {// 用户已经存在
            std::cout << "<head><meta charset=\"UTF-8\"></head>" << std::endl;
            std::cout << "<body><h1>该用户已经存在</h1></body>" << std::endl;
        }
    }
    std::cerr<<"------------------------mysql-end--------------------------"<<std::endl;
    return 0;
}